package pers.xuehongyan.useat.server.service;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pers.xuehongyan.useat.server.enity.Machine;
import pers.xuehongyan.useat.server.enity.Seat;
import pers.xuehongyan.useat.server.enity.Ticket;
import pers.xuehongyan.useat.server.enity.User;
import pers.xuehongyan.useat.server.exception.ServiceException;
import pers.xuehongyan.useat.server.exception.machine.MachineEmptyException;
import pers.xuehongyan.useat.server.exception.machine.MachineFullException;
import pers.xuehongyan.useat.server.exception.machine.MachineNotFoundException;
import pers.xuehongyan.useat.server.exception.seat.SeatNotFoundException;
import pers.xuehongyan.useat.server.manager.MachineManager;
import pers.xuehongyan.useat.server.manager.SeatManager;
import pers.xuehongyan.useat.server.manager.UserManager;
import pers.xuehongyan.useat.server.mapper.TicketMapper;
import pers.xuehongyan.useat.server.utils.TOTPUtils;

import javax.annotation.Resource;
import java.sql.Timestamp;

/**
 * @author xuehongyan
 */
@Service
@Transactional(rollbackFor = {RuntimeException.class, ServiceException.class})
public class SeatService {
    @Resource
    SeatManager seatManager;

    @Resource
    MachineManager machineManager;

    @Resource
    TicketMapper ticketMapper;

    @Resource
    UserManager userManager;

    TOTPUtils totpUtils = new TOTPUtils();

    public String rent(Integer seatId, String userToken) throws ServiceException {
        User user = userManager.getUserByToken(userToken);
        Seat seat = seatManager.getSeatById(seatId);
        Machine machine = machineManager.getMachineById(seat.getMachineId());
        if(machine.isEmpty()) {
            throw new MachineEmptyException(machine);
        }
        seat.setUserId(user.getId());
        seat.setMachineId(null);
        seat.setRented(new Timestamp(System.currentTimeMillis()));
        user.setSeatId(seat.getId());
        machine.decrease();

        userManager.update(user);
        seatManager.update(seat);
        machineManager.update(machine);
        return totpUtils.generateTOTP(seat.getSecret());
    }

    public Ticket giveBack(Integer machineId, String userToken, String totp) throws ServiceException {
        User user = userManager.getUserByToken(userToken);
        Machine machine = machineManager.getMachineById(machineId);
        if(machine.isFull()) {
            throw new MachineFullException(machine);
        }

        Seat seat = seatManager.getSeatById(user.getSeatId());
        if(!totpUtils.generateTOTP(seat.getSecret()).equals(totp)) {
            throw new SeatNotFoundException();
        }
        Timestamp rentStart = seat.getRented();

        Integer price = 10;
        seat.setUserId(null);
        seat.setMachineId(machine.getId());
        seat.setRented(null);
        user.setSeatId(null);
        user.setBalance(user.getBalance() - price);
        machine.increase();

        userManager.update(user);
        seatManager.update(seat);
        machineManager.update(machine);

        Ticket ticket = new Ticket();
        ticket.setUserId(user.getId());
        ticket.setSeatId(seat.getId());
        ticket.setStart(rentStart);
        ticket.setEnd(new Timestamp(System.currentTimeMillis()));

        ticket.setPrice(price);
        ticket.setDiscount(0);
        ticketMapper.insert(ticket);
        return ticket;
    }

    public Integer createSeat(Integer machineId, String secret) throws MachineNotFoundException, MachineFullException {
        Machine machine = machineManager.getMachineById(machineId);
        if(machine.isFull()) {
            throw new MachineFullException(machine);
        }

        Seat seat = new Seat();
        seat.setMachineId(machineId);
        seat.setSecret(secret);
        seatManager.create(seat);

        machine.increase();
        machineManager.update(machine);
        return seat.getId();
    }
}
